﻿using System;
using System.Diagnostics;
using System.Linq;
using Autofac;
using CommandLineParser.Exceptions;
using uTILLIty.Rave.Commandline.Properties;
using uTILLIty.Rave.Core;

namespace uTILLIty.Rave.Commandline
{
	internal class Program
	{
		private static IContainer _container;

		internal static IContainer Container
		{
			get { return _container ?? (_container = CreateContainer()); }
		}

		private static IContainer CreateContainer()
		{
			var builder = new ContainerBuilder();
			builder.RegisterType<CreateCommand>().Named<ICommand>("Create".ToLowerInvariant());
			builder.RegisterType<RunJobCommand>().Named<ICommand>("Job".ToLowerInvariant());
			builder.RegisterType<ReadAclsCommand>().Named<ICommand>("ReadAcls".ToLowerInvariant());
			builder.RegisterModule<IocModule>();
			IContainer container = builder.Build();
			return container;
		}

		static int Main(string[] args)
		{
			FileVersionInfo fileInfo = FileVersionInfo.GetVersionInfo(typeof(Program).Assembly.Location);
			FileVersionInfo coreFileInfo = FileVersionInfo.GetVersionInfo(typeof(IocModule).Assembly.Location);
			// ReSharper disable LocalizableElement
			Console.WriteLine("{0} V. {1}", fileInfo.ProductName, coreFileInfo.ProductVersion);
			// ReSharper restore LocalizableElement
			var parser = new CommandLineParser.CommandLineParser
			{
				ShowUsageOnEmptyCommandline = false,
				CheckMandatoryArguments = true,
				IgnoreCase = false,
				AcceptEqualSignSyntaxForValueArguments = true
			};
			string command;
			args = ExtractCommand(args, out command);
			var target = GetCommand(command);
			if (target == null)
			{
				return -2;
			}
			parser.ExtractArgumentAttributes(target);

			if (args.Length == 0)
			{
				parser.ShowUsage();
				return -1;
			}

			try
			{
				parser.ParseCommandLine(args);
				target.Execute();
				return 0;
			}
			catch (CommandLineException e)
			{
				Console.WriteLine(e.Message);
				parser.ShowUsage();
				return -3;
			}
			catch (Exception e)
			{
				WriteException(e);
				return -4;
			}
			finally
			{
				Trace.Flush();
			}
		}

		internal static void WriteException(Exception e)
		{
#if !DEBUG
			Exception ex = e;
			while (ex.InnerException != null)
				ex = ex.InnerException;

			Console.WriteLine("{1}: {0}", ex.Message, ex.GetType().Name);
#else
			Console.WriteLine(e.ToString());
#endif
		}

		private static string[] ExtractCommand(string[] args, out string command)
		{
			command = "";
			if (args == null || args.Length == 0 || args[0].StartsWith("-"))
				return args;
			command = args[0];
			return args.Skip(1).ToArray();
		}

		private static ICommand GetCommand(string command)
		{
			if (string.IsNullOrEmpty(command) || command.StartsWith("-"))
				command = "Create";

			object target;
			if (Container.TryResolveNamed(command.ToLowerInvariant(), typeof(ICommand), out target))
				return (ICommand)target;

			Console.WriteLine(Resources.UnknownCommand, command);
			return null;
		}
	}
}
